﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;

namespace BitPortal.Business
{
    public static partial class DataBLL
    {
        public static string GetTypeOfProperty(this object data, string property)
        {
            return data.GetPropertyValue(property).GetType().Name;
        }

        public static object GetValueInType(this object input, object type)
        {
            if (type.Equals("1") || type.Equals("Boolean"))
            {
                return Convert.ToBoolean(input);
            }
            else if (type.Equals("2") || type.Equals("DateTime"))
            {
                return Convert.ToDateTime(input);
            }
            else if (type.Equals("3") || type.Equals("Decimal"))
            {
                return Convert.ToDecimal(input);
            }
            else if (type.Equals("4") || type.Equals("Int32") || type.Equals("Interger"))
            {
                return Convert.ToInt32(input);
            }
            else if (type.Equals("5") || type.Equals("Int64"))
            {
                return Convert.ToInt64(input);
            }
            else if (type.Equals("6") || type.Equals("Double"))
            {
                return Convert.ToDouble(input);
            }
            else
            {
                return input.ToString();
            }
        }

        public static object GetPropertyValue(this object obj, string property, char splitor = '_')
        {
            if (property.Contains(splitor))
            {
                object value = obj;
                foreach (string s in property.Split(splitor))
                {
                    value = value.GetType().GetProperty(s).GetValue(value, null);
                }
                return value;
            }
            return obj.GetType().GetProperty(property).GetValue(obj, null);
        }

        /// <summary>
        /// Menthode to filter, sort and paging data <br/>
        /// Condition: Type-Value-Field-Comparison<br/>
        /// 1-Boolean;2-Datetime;3-Decimal;4-Int32;5-Int64;6-Double;Else-String
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="conditions"></param>
        /// <param name="sort"></param>
        /// <param name="dir"></param>
        /// <param name="thenby"></param>
        /// <param name="thenbyDir"></param>
        /// <param name="start"></param>
        /// <param name="limit"></param>
        /// <param name="conditionSplitor"></param>
        /// <returns></returns>
        public static List<T> DataProcessing<T>(this List<T> source, List<String> conditions, string sort, string dir = "asc", string thenby = null, string thenbyDir = null, int start = -1, int limit = -1, char conditionSplitor = '-')
        {
            //Filtering
            //Type,value,field,comparison
            if (conditions != null)
            {
                foreach (string str in conditions)
                {
                    if (source == null || source.Count == 0) return source;
                    string[] parameters = str.Split(conditionSplitor);
                    string type = source.First().GetTypeOfProperty(parameters[2]);
                    object value;
                    if (string.IsNullOrEmpty(parameters[0]))
                    {
                        value = parameters[1].GetValueInType(type);
                    }
                    else
                    {
                        value = parameters[1].GetValueInType(parameters[0]);
                    }
                    source.RemoveAll(item =>
                        {
                            object oValue = item.GetPropertyValue(parameters[2]);

                            IComparable cItem = oValue as IComparable;
                            parameters[3] = parameters[3].Trim().ToLower();
                            if (parameters[3].Equals("eq")) return !cItem.Equals(value);
                            if (parameters[3].Equals("neq")) return cItem.Equals(value);
                            if (parameters[3].Equals("gt")) return cItem.CompareTo(value) < 1;
                            if (parameters[3].Equals("lt")) return cItem.CompareTo(value) > -1;
                            if (parameters[3].Equals("ctn")) return oValue.ToString().IndexOf(value.ToString(), StringComparison.OrdinalIgnoreCase) < 0;
                            if (parameters[3].Equals("stw")) return !oValue.ToString().StartsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase);
                            return true;
                        }
                        );
                }
            }
            //Sorting
            if (sort != null)
            {
                source = (thenby == null || thenbyDir == null) ? source.AsQueryable().OrderBy(ent => ent, new BitComparer<T>(sort, dir)).ToList() : source.AsQueryable().OrderBy(ent => ent, new BitComparer<T>(sort, dir)).ThenBy(ent => ent, new BitComparer<T>(thenby, thenbyDir)).ToList();
            }
            //Paging
            List<T> rangeData = source;
            if (start + limit > source.Count)
            {
                limit = source.Count - start;
            }
            rangeData = (start < 0 || limit < 0) ? source : source.GetRange(start, limit);
            //count = source.Count;
            return rangeData;
        }

    }
    public class BitComparer<T> : IComparer<T>
    {
        public string sort { set; get; }
        public string dir { set; get; }
        public BitComparer() { }
        public BitComparer(string s, string d)
        {
            this.sort = s;
            this.dir = d;
        }
        public int Compare(T x, T y)
        {
            object a;
            object b;

            int direction = (dir.ToLower().Equals("desc") ? -1 : 1);

            if (sort.Contains("_"))
            {
                string[] l = sort.Split('_');
                a = x;
                b = y;
                foreach (string s in l)
                {
                    if (!string.IsNullOrEmpty(s))
                    {
                        try
                        {
                            a = a.GetType().GetProperty(s).GetValue(a, null);
                            b = b.GetType().GetProperty(s).GetValue(b, null);
                        }
                        catch { throw new Exception(s); }
                    }
                }
            }
            else
            {
                a = x.GetType().GetProperty(sort).GetValue(x, null);
                b = y.GetType().GetProperty(sort).GetValue(y, null);
            }
            return CaseInsensitiveComparer.Default.Compare(a, b) * direction;
        }

    }
}